﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml.Linq;

namespace CourseMaster
{
    public partial class TaskMaster : Form
    {
        public TaskMaster()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
			if (treeView1.SelectedNode == null)
				return;
            // Добавить строку к списку
            if (!(treeView1.SelectedNode.Tag is Task))
                return;

            TreeNode node = treeView1.SelectedNode;
            String[] tokens = textBox1.Text.Split(new char[] { ' ' });
            foreach (String token in tokens)
            {
                bool f = false;
                // Найти такой же
                foreach (TreeNode xnode in node.Nodes)
                {
                    Element se = xnode.Tag as Element;
                    if (se.Text == token)
                    {
                        node = xnode;
                        f = true;
                        break;
                    }
                }
                if (!f)
                {
                    // Создать новый элемент
                    Element element = new Element();
                    element.Text = token;
                    TreeNode subnode = new TreeNode(element.Text);
                    subnode.Tag = element;
                    node.Nodes.Add(subnode);
                    node = subnode;
                }
            }
        }

        private void OnNodeSelect(object sender, TreeViewEventArgs e)
        {
            // Выбрать элемент
            propertyGrid1.SelectedObject = treeView1.SelectedNode.Tag;
            if (treeView1.SelectedNode.Tag is Element)
                GenerateCode();
        }

        void GenerateCode()
        {
            String code = "";

            TreeNode node = treeView1.SelectedNode;
            while (node.Tag is Element)
            {
                Element e = node.Tag as Element;
                String s = e.Text;
                for (int i = 0; i < e.SpaceCount; ++i)
                    s += " ";
                for (int i = 0; i < e.TabsCount; ++i)
                    s = "\t" + s;
                if (e.NewLine)
                    s = "\n" + s;
                code = s + code;
                node = node.Parent;
            }

            Task task = node.Tag as Task;
            String before = task.CodeBefore;

            int index = 0;
            String[] lines = before.Split(new string[] { "\\n" }, StringSplitOptions.RemoveEmptyEntries);
            before = "";
            foreach(String line in lines)
            {
                before += line + "\n";
            }
            
            code = before + code;

            richTextBox1.Text = code;
        }

        private void OnPropertyChanged(object s, PropertyValueChangedEventArgs e)
        {
            if (propertyGrid1.SelectedObject is Topic)
            {
                treeView1.SelectedNode.Text = (propertyGrid1.SelectedObject as Topic).Name;
            }

            if (propertyGrid1.SelectedObject is Task)
            {
                treeView1.SelectedNode.Text = (propertyGrid1.SelectedObject as Task).Description;
            }

            if (propertyGrid1.SelectedObject is Element)
            {
                treeView1.SelectedNode.Text = (propertyGrid1.SelectedObject as Element).Text;
                // Заново сгенерировать текст
            }
        }

        private void newToolStripButton_Click(object sender, EventArgs e)
        {
            // Добавить новое задание
			if (treeView1.SelectedNode == null)
				return;

            if (!(treeView1.SelectedNode.Tag is Topic))
                return;

            Task task = new Task();
            TreeNode node = new TreeNode(task.Description);
            node.Tag = task;

            treeView1.SelectedNode.Nodes.Add(node);
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            // Удалить узел
			
			if (treeView1.SelectedNode == null)
				return;

			treeView1.SelectedNode.Parent.Nodes.Remove(treeView1.SelectedNode);
        }

        private void openToolStripButton_Click(object sender, EventArgs e)
        {
            // Добавить топик
            Topic topic = new Topic();
            topic.Name = "topic";

            TreeNode node = new TreeNode();
			node.ImageKey = "Topic";
			node.SelectedImageKey = "Topic";
            node.Tag = topic;
            node.Text = topic.Name;

            treeView1.Nodes.Add(node);
        }

        private void saveToolStripButton_Click(object sender, EventArgs e)
        {
			SaveFileDialog dlg = new SaveFileDialog();
			dlg.ShowDialog();

			if (dlg.FileName == null)
				return;

			XElement root = new XElement("Root");
			XElement courseElement = new XElement("Course");
			XElement tokensElement = new XElement("Tokens");

			root.Add(courseElement);
			root.Add(tokensElement);

			foreach (TreeNode topicNode in treeView1.Nodes)
			{
				XElement topicElement = new XElement("Topic");
				courseElement.Add(topicElement);

				Topic topic = topicNode.Tag as Topic;

				topicElement.SetAttributeValue("Name", topic.Name);
				topicElement.SetAttributeValue("NextLevel", topic.NextLevel);
				foreach (TreeNode taskNode in topicNode.Nodes)
				{
					XElement taskElement = new XElement("Task");
					topicElement.Add(taskElement);

					Task task = taskNode.Tag as Task;

					taskElement.SetAttributeValue("Description", task.Description);
					taskElement.SetAttributeValue("Code", task.CodeBefore);
					taskElement.SetAttributeValue("StepSize", task.StepSize);

					foreach (TreeNode tokenNode in taskNode.Nodes)
					{
						SaveNode(tokenNode, taskElement);
					}
				}

			}

			foreach (String token in textBox2.Lines)
			{
				XElement tokenElement = new XElement("Token");
				tokenElement.SetAttributeValue("Text", token);
				tokensElement.Add(tokenElement);
			}

			XDocument document = new XDocument();
			document.Add(root);
			document.Save(dlg.FileName);

        }

        void SaveNode(TreeNode node, XElement parentElement)
		{
			XElement tokenElement = new XElement("Token");
			Element token = node.Tag as Element;

			parentElement.Add(tokenElement);

			tokenElement.SetAttributeValue("Spaces", token.SpaceCount);
			tokenElement.SetAttributeValue("Tabs", token.TabsCount);
			tokenElement.SetAttributeValue("NewLine", token.NewLine);
			tokenElement.SetAttributeValue("Price", token.AdditionalScore);
			tokenElement.SetAttributeValue("Text", token.Text);

            foreach (TreeNode subnode in node.Nodes)
            {
				SaveNode(subnode, tokenElement);
            }
        }

        void OpenTXTFile(String fileName)
        {
			String save = "";
			try
			{
				save = File.ReadAllText(fileName, Encoding.GetEncoding(1251));
			}
			catch
			{
			}
			List<TreeNode> nodes = Element.ParseText(save);

			treeView1.Nodes.Clear();
			foreach (TreeNode node in nodes)
				treeView1.Nodes.Add(node);
        }

		/// <summary>
		/// Разбирает XML-элемент описывающий лексему
		/// </summary>
		/// <param name="tokenElement">Элемент с описанием лексемы</param>
		/// <returns>Узел дерева: лексема</returns>
		TreeNode ParseXMLToken(XElement tokenElement)
		{
			Element token = new Element();

			token.IsCorrect = true;
			token.NewLine = tokenElement.Attribute("NewLine") != null ? bool.Parse(tokenElement.Attribute("NewLine").Value) : false;
			token.SpaceCount = tokenElement.Attribute("Spaces") != null ? int.Parse(tokenElement.Attribute("Spaces").Value) : 1;
			token.TabsCount = tokenElement.Attribute("Tabs") != null ? int.Parse(tokenElement.Attribute("Tabs").Value) : 0;
			token.Text = tokenElement.Attribute("Text").Value;
			token.AdditionalScore = tokenElement.Attribute("Price") != null ? int.Parse(tokenElement.Attribute("Price").Value) : 1;
			
			TreeNode tokenNode = new TreeNode(token.Text);
			tokenNode.Tag = token;
			foreach (XElement element in tokenElement.Elements("Token"))
			{
				tokenNode.Nodes.Add(ParseXMLToken(element));
			}

			return tokenNode;
		}

		TreeNode ParseXMLTopic(XElement topicElement)
		{
			Topic topic = new Topic();
			topic.NextLevel = topicElement.Attribute("NextLevel") != null ? int.Parse(topicElement.Attribute("NextLevel").Value) : 1;
			topic.Name = topicElement.Attribute("Name").Value; 

			TreeNode topicNode = new TreeNode(topic.Name);
			topicNode.Tag = topic;
			foreach (XElement taskElement in topicElement.Elements("Task"))
			{
				topicNode.Nodes.Add(ParseXMLTask(taskElement));
			}

			return topicNode;
		}

		TreeNode ParseXMLTask(XElement taskElement)
		{
			Task task = new Task();

			task.Description = taskElement.Attribute("Description").Value;
			task.CodeBefore = taskElement.Attribute("Code").Value;
			task.StepSize = taskElement.Attribute("StepSize") != null ? int.Parse(taskElement.Attribute("StepSize").Value) : 3;

			TreeNode taskNode = new TreeNode(task.Description);
			taskNode.Tag = task;

			foreach (XElement tokenElement in taskElement.Elements("Token"))
			{
				taskNode.Nodes.Add(ParseXMLToken(tokenElement));
			}

			return taskNode;
		}

		void OpenXMLFile(String fileName)
		{
			treeView1.Nodes.Clear();
			XDocument document = XDocument.Load(fileName);
			XElement rootElement = document.Root;
			XElement courseElement = rootElement.Element("Course");
			XElement tokensElement = rootElement.Element("Tokens");

			foreach (XElement topicElement in courseElement.Elements("Topic"))
			{
				treeView1.Nodes.Add(ParseXMLTopic(topicElement));
			}

			List<String> tokens = new List<string>();
			foreach (XElement tokenElement in tokensElement.Elements("Token"))
			{
				tokens.Add(tokenElement.Attribute("Text").Value);
			}

			textBox2.Lines = tokens.ToArray();
		}

		private void toolStripButton2_Click(object sender, EventArgs e)
		{
			OpenFileDialog dlg = new OpenFileDialog();
			dlg.Filter = "XML-файл (*.xml)|*.xml|Текстовый файл (*.txt)|*.txt|(*.*)|*.*";

			dlg.ShowDialog();

			if (dlg.FileName == null)
				return;

			switch (Path.GetExtension(dlg.FileName))
			{
				case ".xml":
					OpenXMLFile(dlg.FileName);
					break;
				case ".txt":
					OpenTXTFile(dlg.FileName);
					break;
			}

		}
    }
}
